﻿using System;
using System.Collections.Generic;
using System.Globalization;
using LLoger;
using LimitatorInterfaces;
using LimitatorInterfaces.LoadServices;
using MicexFileLoader;

namespace LoadServices
{
    public class MicexFileLoadParser : ServiceBase, ILoadParser
    {
        private Dictionary<string, string> _depoSett = new Dictionary<string, string>();
        private Dictionary<string, string> _moneySett = new Dictionary<string, string>();
        private string _moneyLimitHdr;
        private string _depoLimitHdr;

        public MicexFileLoadParser(string configPath, ILogWriter logWriter)
            : base(configPath, logWriter)
        {
            //_moneySett.Add(Resources.ActiveCode, (string)GetSettingsValue(Resources.ActiveCode));
            _moneySett.Add(Res.ClientCode, (string)GetSettingsValue(Res.ClientCode));
            _moneySett.Add(Res.Value, (string)GetSettingsValue(Res.Value));
            _moneySett.Add(Res.IsMoney, (string)GetSettingsValue(Res.IsMoney));
            _moneySett.Add(Res.Leverage, (string)GetSettingsValue(Res.Leverage));

            _moneyLimitHdr = _moneySett[Res.IsMoney];

            _depoSett.Add(Res.ActiveCode, (string)GetSettingsValue(Res.ActiveCode));
            _depoSett.Add(Res.ClientCode, (string)GetSettingsValue(Res.ClientCode));
            _depoSett.Add(Res.Value, (string)GetSettingsValue(Res.Value));
            _depoSett.Add(Res.WaPrice, (string)GetSettingsValue(Res.WaPrice));


        }

        public LimitEntity ParceFrom(object param)
        {
            try
            {
                if (param == null) throw
                    new ArgumentNullException("param");


                if (param.GetType() != typeof(string))
                    throw new ParserException(string.Format("Парсер типа {0} может принимать для разбора только строки стандартного файла лимитов ММВБ ИТС QUIK", this.ToString()));

                var limStr = param.ToString();

                return IsMoneyLimit(limStr) ? ParseLim(limStr, _moneySett) : ParseLim(limStr, _depoSett);
            }
            catch (Exception ex)
            {
                var msg = "Не удалось извлеч лимит: " + param;
                LogWriter.WriteLine(ex, "Не удалось извлеч лимит: " + param);
                throw new ParserException(msg, ex);
            }
        }

        private bool IsMoneyLimit(string limStr)
        {
            return limStr.StartsWith(_moneyLimitHdr);
        }

        private LimitEntity ParseLim(string limStr, Dictionary<string, string> settDictionary)
        {
            // разбить входную строку лимита на пары Ключ=Значение
            var splitedStr = limStr.Split(';');

            Dictionary<string, string> result = new Dictionary<string, string>();

            // Каждую пару проверить распарсить 
            foreach (var s in splitedStr)
            {
                var currParam = s.Trim();

                // проверить есть ли параметр в словаре парсера settDictionary
                foreach (var setting in settDictionary)
                {
                    var parsedValue = CheckAndParceParam(currParam, setting.Value);

                    if (string.IsNullOrEmpty(parsedValue))
                        continue;

                    result.Add(setting.Key, parsedValue);
                }
            }

            if (result.ContainsKey(Res.IsMoney))
                result[Res.IsMoney] = true.ToString();
            else
                result.Add(Res.IsMoney, false.ToString());

            LimitEntity lim = CreateLimit(values: result);

            if (lim == null)
                throw new ParserException("Ошибка при разборе строки лимита: " + limStr);

            return lim;

        }

        private LimitEntity CreateLimit(Dictionary<string, string> values)
        {
            LimitEntity lim = new LimitEntity();

            lim.IsMoney = bool.Parse(CheckAttr(Res.IsMoney, values, true, true));

            bool isMoney = lim.IsMoney;
            bool isDepo = !isMoney;

            lim.ClientCode = CheckAttr(Res.ClientCode, values, true, true);
            lim.ActiveCode = CheckAttr(Res.ActiveCode, values, isDepo, isDepo);
            //lim.TradeSystem = CheckAttr(Res., values);
            lim.Value = decimal.Parse(CheckAttr(Res.Value, values, true, true).Replace('.', ','));
            lim.Leverage = decimal.Parse(CheckAttr(Res.Leverage, values, defValue: "0").Replace('.', ','));
            lim.WaPrice = decimal.Parse(CheckAttr(Res.WaPrice, values, defValue: "0").Replace('.', ','));

            return lim;
        }

        /// <summary>
        /// Проверяет наличие аттрибута <paramref name="attr"/> в словаре param <paramref name="source"/>
        /// </summary>
        /// <param name="attr">исковмый атрибут</param>
        /// <param name="source">источник атрибутова</param>
        /// <param name="throwIfAbsent">выбросить исключение, если атрибут ненайден</param>
        /// <param name="throwIfEmpty">Выбросить исключение, если нет значения у атрибута</param>
        /// <returns></returns>
        private string CheckAttr(string attr, Dictionary<string, string> source, bool throwIfAbsent = false, bool throwIfEmpty = false, string defValue = "")
        {
            if (!source.ContainsKey(attr))
                if (throwIfAbsent)
                    throw new ParserException(string.Format("Обязательный атрибут {0} не найден", attr));
                else
                    return string.IsNullOrWhiteSpace(defValue) ? null : defValue;


            var res = source[attr];

            if (string.IsNullOrWhiteSpace(res))
                if (throwIfEmpty)
                    throw new ParserException(string.Format("Обязательный атрибут {0} присутствует, но нет значения", attr));


            return string.IsNullOrWhiteSpace(res) ?
                (string.IsNullOrWhiteSpace(defValue) ? defValue : res)
                : res;

        }

        /// <summary>
        /// Сравнивает 
        /// </summary>
        /// <param name="currParam">проверемая пара Ключ=Значение</param>
        /// <param name="lookingForParam">Ископый в паре <paramref name="currParam"/> ключ </param>
        /// <returns></returns>
        private string CheckAndParceParam(string currParam, string lookingForParam)
        {
            if (currParam.StartsWith(lookingForParam))
                return GetLimitParamValue(currParam, lookingForParam);

            return null;
        }

        private string GetLimitParamValue(string s, string param)
        {
            string[] val = new string[2];

            if (s.StartsWith(param))
                val = s.Split('=');

            return val[1].Trim();
        }
    }
}